package com.zbj.data.jpa.aspect;

import com.google.common.collect.Maps;
import com.zbj.data.jpa.datasource.DBType;
import com.zbj.data.jpa.datasource.DynamicDataSourceHolder;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.util.ObjectUtils;

import java.lang.reflect.Method;
import java.util.Map;

/**
 * DynamicDataSourceAspect
 *
 * @author weigang
 * @create 2017-09-10
 **/
@Aspect
@Component
@Order(Ordered.HIGHEST_PRECEDENCE - 1)
@Slf4j
public class DynamicDataSourceAspect {

	private Map<String, String> targetDataSourceMap = Maps.newConcurrentMap();

	/**
	 * load reload 从主库读，原因是用户在reload的时候主从之前有延迟，会产生数据不一致
	 */
	@Value("${supper.select.key:select,get,find,query,load,reload}")
	private String supperSelectKey;

	/**
	 * 根据路径切 根据方法名选择数据源
	 */
	@Pointcut(value = "execution(public * com.zbj.data.jpa.service.impl.*.*(..))")
	public void dataSourceAspect() {

	}

	@Around("dataSourceAspect()")
	public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
		String targetDataSource = DBType.MASTER;
		String cacheValue = targetDataSourceMap.get(joinPoint.toString());
		if (ObjectUtils.isEmpty(cacheValue)) {
			Signature signature = joinPoint.getSignature();
			if (signature instanceof MethodSignature) {
				MethodSignature methodSignature = (MethodSignature) signature;
				Method targetMethod = methodSignature.getMethod();
				Object target = joinPoint.getTarget();
				Method implMethod = null;
				try {
					implMethod = target.getClass().getMethod(targetMethod.getName(), targetMethod.getParameterTypes());
				} catch (NoSuchMethodException e) {
					log.warn(targetMethod.toString() + " not exist" + e.toString());
				}

				if(!ObjectUtils.isEmpty(implMethod)){
					String methodName = implMethod.getName();
					String[] splitArr = supperSelectKey.split(",");
					for (String split : splitArr) {
						if (methodName.startsWith(split)) {
							targetDataSource = DBType.SLAVE;
							break;
						}
					}
				}

				targetDataSourceMap.put(joinPoint.toString(), targetDataSource);
			}
		} else {
			targetDataSource = cacheValue;
		}
		DynamicDataSourceHolder.setDataSource(targetDataSource);

		Object proceed = joinPoint.proceed(); // 方法调用
		DynamicDataSourceHolder.clearDataSource();

		return proceed;
	}

	public String getSupperSelectKey() {
		return supperSelectKey;
	}

	public void setSupperSelectKey(String supperSelectKey) {
		this.supperSelectKey = supperSelectKey;
	}
}
